package com.cskaoyan.javase.oop3._1interface._0introduction;

/**
 * 接口的引入
 * 现在我们有了新需求：一部分猫和狗，经过了特殊训练，能够直立行走了。那么这群特殊的猫和狗，怎么描述它们呢？
 *
 * 分析：
 * 部分猫和狗经过特殊训练，才能够直立行走。
 * 所以不可能直接加个方法到Cat类和Dog类中，不是所有猫狗都有这个行为。
 * 而特殊的猫狗仍然是猫和狗，所以它们肯定还要继承猫和狗这两个类。
 * 可能很多同学，这时候想到的就是：重新定义两个新的猫狗类（比如超级狗和猫）继承猫狗，然后给出直立行走的方法就算完事了。
 * 这样做不是不行，需求是实现了，但还有一些小问题：
 *      1.一方面没有体现代码复用。
 *      2.更重要的是，没有体现出特殊训练的过程。
 *          假如还有一些动物也要直立行走，增加这个行为，如何体现出规范性、标准性呢？体现出它们是特殊的经过训练的动物呢？
 *
 * 这里我们想到了抽象类，因为抽象类中抽象方法，可以强制约束子类实现它，这样就是一种标准和规范，体现了它经过了特殊训练，和之前不同了。
 *
 * 于是我们定义抽象类，给出抽象方法，让超级猫狗类去继承这个抽象类，可行吗？
 *
 * 理想很美好，现实很骨感。显然做不到
 *  因为Java不支持多继承。已经继承一个类后,不能再次继承一个抽象类.
 *
 *  除开这点这么做也不是完美的，问题是：
 *
 * 这个抽象类里面是对功能和行为的抽象，缺少属性（单独一个直立行走的行为是一个什么对象？）所以单独的行为不应该被抽象为类，不符合类的定义。
 * 继承这个抽象类也不符合继承的"is-a"关系，这里不适用继承（还是上面那句话，行为根本不是个体）
 *
 * 于是，我们就迫切需要一种全新的数据类型，这种全新的数据类型：
 *      1.不强调属性的抽象，只强调行为的抽象，"继承"它表示功能的扩展。
 *      2.在一个类继承某个类后，还能继续"继承"，不受Java单继承限制。
 *      3.没有"is-a"这种继承关系的限制。
 *      4.最好还有抽象方法。（因为它能表示规范和标准）
 *
 * 这种全新的数据类型，就是接口（interface）。
 *
 * 接口的语法:
 * [访问权限修饰符] interface 接口名{}
 * 解释:
 *      1.访问权限修饰符,和class是一样的,只能有两种访问级别,public和默认权限.
 *      2.interface关键字是声明接口的关键字,等同于class关键字.接口和类class是Java当中同等级别的数据类型,都是引用数据类型
 *      3.接口名同样"大驼峰",同样最好"见名知意"
 *
 * 接口体的定义
 *      接口中允许定义抽象方法.
 *
 * 接口的"继承":
 *      一个普通类是可以"继承"接口的,当然用专业的术语,称之为"实现",普通类实现了接口,使用关键字"implements"
 *      并且一个类可以在继承某个类的同时再去实现一个接口,需要注意的是,如果有继承还有实现,需要先继承,再实现
 *      实现接口的类,可以称之为接口的子类
 *      接口可以称之为这个子类的父接口(父类)
 *      这意味着父接口引用也可以指向不同的实现子类对象,并且他们的使用和父类引用指向子类对象,没有区别
 *
 * 接口的实现
 *      需要注意的是,一个类可以同时实现多个接口
 *      不是单实现
 *      而是多实现
 *
 *
 * 使用接口有如下优点：
 *      1.接口不受单继承限制，这是接口非常重要的优点。
 *      2.接口不是类，它和它的实现类，也不需要存在"is-a"关系，接口比抽象类的使用更加灵活。
 *      3.程序开发中将接口和它的实现类之间的关系，称之为"like-a"关系。只要是实现了Xxx的功能，就像Xxx。
 *          比如说一个盒子,它只要实现了制冷和制热的功能(空调的空调),那么它就像一台空调.
 *          这就意味着接口表示一种开发标准，一种规范。表示对功能的扩展，它只关注行为，不关注属性。
 *
 * @since 16:00
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 父接口引用指向子类对象
        SpecialSkills ss = new SuperCat();
        // ss.shout();
        ss.walkUpright();

        ss = new SuperDog();
        ss.walkUpright();

        // 问题: SuperCat可以有几种方式创建对象?
        SuperCat sc = new SuperCat();
        Cat c = new SuperCat();
        Object o = new SuperCat();
        SpecialSkills ss2 = new SuperDog();
        A a = new SuperCat();
    }
}

abstract class Animal {
    public abstract void shout();
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}
class SuperCat extends Cat implements SpecialSkills,A{
    @Override
    public void walkUpright(){
        System.out.println("我是超威蓝猫,我直立行走不是很正常!");
    }

    @Override
    public void test() {
        System.out.println("hello world!");
    }
}
class SuperDog extends Dog implements SpecialSkills{
    @Override
    public void walkUpright(){
        System.out.println("我是汪汪特工队,直立行走不是很正常!");
    }
}
abstract class BaseSpecialSkill{
    public abstract void walkUpright();
}

interface SpecialSkills{
    public abstract void walkUpright();
}
interface A{
    public abstract void test();
}
